"""
优化器
为什么需要优化器
1.自动化参数更新
2.加速收敛
3.避免局部最优
"""
# SGD 简单基础 基础教学、简单模型
# ADAM 自适应学利率 大多数深度学习任务
# RMSprop 适应学习率 RNN网络
# Adagrad 参数独立学习库 稀疏数据
import torch
import torch.optim as optim
#1.定义模型
model=MyModel()
#2.创建优化器实例
optimizer=optim.Adam(model.parameter(),lr=0.001)
#3.循环训练
for epoch in range(epochs):
    #向前传播
    outputs=model(inputs)
    loss= criterion(outputs,labels)
    
    #反向传播
    optimizer.zero_grad() #清空参数的梯度缓存
    loss.backward() #计算梯度

    #参数更新
    optimizer.step() #执行单次参数更新
#state_dict():获取优化器状态（可用于保存和加载）
#load_state_dict()：加载优化器状态

"""
常用优化器详解
"""
#SGD（随机梯度下降）
#optim.SGD(params,lr=0.01,momentum=0,dampening=0,weight_decay=0,nesterov=False)
#lr(float)：学习率（默认0.01）
#momentum(float)：动量因子（默认0）
#weight_decay(float)：L2正则化系数（默认0）
#最简单的优化算法，可以添加动量项加速收敛
#适合作为基准比较

#Adam(自适应矩估计)
#optim.Adam(params,lr=0.001,betas=(0.9,0.9999),eps=1e-08,weight_decay=0,amsgrad=False)
#betas(Tuple[float,flaot]:用于计算梯度和地图平方的移动平均系数)
#eps(float):数值稳定项（默认1e-8）
#amsgrad(bool):是否使用AMSGrad变体（默认False）

"""
优化器高级技巧
"""
#学习率调度
from torch.optim.lr_scheduler import StepLR
optimizer=optim.SGD(model.parameter(),lr=0.1)
scheduler=StepLR(optimizer,step_size=30,gamma=0.1)

for epoch in range(100):
    train(...)
    validate(...)
    scheduler.step()#更新学习率

#参数分组优化
optim.SGD([
    {'params':model.base.parameters()},
    {'params':model.classifier.parameters()}
])

#梯度裁剪
torch.nn.utils.clip_grad_norm_(model.parameters(),max_norm=1.0)
